這篇文章我們將說來談談《 Patterns of Enterprise Application Architecture - Martin Fowler 》書中 DataSource 層級的其中一種 pattern
RowDataGateway
它事實上是上很像我們上一章節提到的『 TableDataGateway 』只是他的單位從 table 變成 row,說實話我覺得一單位變化也有點像是 domain 層的『 table module → domain model 』,不過我覺得他有多個變化,就是將可能會多筆的 query 操作拉到一個叫『 finder 』的地方處理。
然後它實際上的定義就我自已的理解為 :
有一個 class 以 table row 為單位,然後這個地方只處理『 單筆 』,而多筆的 query,則會在以書中範例為『 Finder 』的地方處理。
概念上真有點像是 CQRS,但 CQRS 我目前還不太熟,所以等研究完後,在來補這的差異。
然後書中有提到作者說他什麼使用情境。
The choice of Row Data Gateway often takes two steps: first whether to use a gateway at all and second whether to use Row Data Gateway or Table Data Gateway (144)
const mockDbData = [
{
id: 1,
username: 'mark',
age: 19,
company: 'hahow'
},
{
id: 2,
username: 'ian',
age: 19,
company: 'amazon'
}
]
function executeSql(sql: string){
return mockDbData
}
class PersonFinder{
find(id: number): PersonGateway{
const sql = `SELECT * FROM person WHERE id=${id}`
const resultSet = executeSql(sql)
const data = resultSet[0]
return new PersonGateway(data.id, data,username, data.age, data.company)
}
findByCompany(company: string): PersonGateway[]{
const result: PersonGateway[] = []
const sql = `SELECT * FROM person WHERE company=${company}`
const resultSet = executeSql(sql)
for (const data of resultSet) {
result.push(new PersonGateway(data.id, data,username, data.age, data.company))
}
return result
}
}
class PersonGateway{
id: number
username: string
age: number
company: string
constructor(id: number, username: string, age: number, company: string){
this.id = id
this.username = username
this.age= age
this.company = company
}
update(): void{
console.log(`UPDATE person SET username=${this.username}, age=${this.age}, company=${this.company} WHERE id=${this.id}`)
}
insert(): void{
console.log(`INSERT INTO person (username, age, company) VALUES(${this.username}, ${this.age}, ${this.company})`)
}
}
然後我們 domain 層使用 table module 來使用 rowDataGateway 的情況,如下。
class PersonTableModule{
personFinder: PersonFinder
constructor(personFinder){
this.personFinder = personFinder
}
register(username: string, age: number , company: string){
// 假設有個業務需求為公司有限定人數 limit = 10
const personsInCompany: PersonGateway[] =this.personFinder.findByCompany(company)
if(personsInCompany.length >= 10) throw Error('公司人數已達限制')
const person: PersonGateway = new PersonGateway(username, age, company)
person.insert()
}
}
我覺得他有將 Query 多筆的拉出來一個 Finder,這點應該也可以解釋為什麼會有 CQRS 的存在,因為 RowDatagateway 本身就代表每個 row 的實體,那這種情況下,如果沒有個 finder 來專門處理多筆的情況,就會生出一堆 RowDatagateway,有可能導致性能不佳。
我覺得相識的概念有 :